package com.drawu.drawuspring.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.drawu.drawuspring.constants.BehaviorConstants;
import com.drawu.drawuspring.constants.JwtClaimsConstant;
import com.drawu.drawuspring.domain.DTO.FocusBehaviorDto;
import com.drawu.drawuspring.domain.DTO.UserDTO;
import com.drawu.drawuspring.domain.DTO.UserLoginDTO;
import com.drawu.drawuspring.domain.Result;
import com.drawu.drawuspring.domain.VO.UserLoginVO;
import com.drawu.drawuspring.domain.VO.UserVO;
import com.drawu.drawuspring.domain.po.Users;
import com.drawu.drawuspring.enums.AppHttpCodeEnum;
import com.drawu.drawuspring.mapper.UserMapper;


import com.drawu.drawuspring.service.IImagesService;
import com.drawu.drawuspring.service.IUsersService;
import com.drawu.drawuspring.utils.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, Users> implements IUsersService {

    //微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";


    private final StringRedisTemplate redisTemplate;
    private final JwtProperties jwtProperties;
    private final WeChatProperties weChatProperties;
    private final IImagesService imagesService;

    /**
     * 登录
     *
     */
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        String openid = getOpenid(userLoginDTO.getCode());
        //判断openid是否为空，如果为空表示登录失败，抛出业务异常
        if(openid == null){
            throw new RuntimeException("登录失败，请稍后再试");
        }
//        Users user = getUser(openid);
        Users user = getOne(new QueryWrapper<Users>().eq("openid", openid));
        //如果是新用户，自动完成注册
        if(user == null){
            user=Users.builder()
                   .openid(openid)
                   .createTime(LocalDateTime.now()).build();
            user.setCreateTime(LocalDateTime.now());
            user.setNickname("捉友" + user.getOpenid().substring(user.getOpenid().length() - 5, user.getOpenid().length()));
            user.setSex(0);
            user.setSignature("这个人很懒，什么都没留下");
            user.setAvatarUrl("https://drawu.obs.cn-south-1.myhuaweicloud.com/avatars/default.png");
            save(user);
        }
        //为微信用户生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID,user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);

        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();
        return  userLoginVO;
    }


    // 登录

    /**
     * 调用微信接口服务，获取微信用户的openid
     */
    private String getOpenid(String code){
        //调用微信接口服务，获得当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        map.put("appid",weChatProperties.getAppid());
        map.put("secret",weChatProperties.getSecret());
        map.put("js_code",code);
        map.put("grant_type","authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        return openid;
    }

    // 获取用户信息
//    public UserVO getUser(String openid) {
//        UserVO userVO = userMapper.getUser(openid);
//        if (userVO != null) {
//            return userVO;
//        } else {
//            StringBuilder sb = new StringBuilder();
//            String nickname = sb.append("用户").append(openid.substring(openid.length() - 5, openid.length())).toString();
//            userMapper.insertUser(openid, nickname);
//            return userMapper.getUser(openid);
//        }
//    }
// 获取用户信息
    @Override
    public Result<UserVO> getUser() {
        Users user = AppThreadLocalUtil.getUser();
        if (user.getId() == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Users users = getById(user.getId());
        UserVO userVO = BeanUtil.copyProperties(users, UserVO.class);
        return Result.success(userVO);
    }

    @Override
    public Result<List<Users>> getUserList() {
        List<Users> list = list();
        return Result.success(list);
    }

    /**
     * 保存用户信息
     *
     */
    @Override
    public Result saveUserData(UserDTO userDTO) {
        Users user = AppThreadLocalUtil.getUser();
        // : 校验参数
        if (userDTO == null  || user.getId() == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        // : 更新用户信息
        Users users = BeanUtil.copyProperties(userDTO, Users.class);
        updateById(users);
        return Result.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 上传头像
     *
     */
    @Override
    public Result uploadAvatar(MultipartFile mpFile, Integer userId) {
        String image = imagesService.uploadImage(mpFile, "avatars");
        if (image == null) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_IMAGE_FORMAT_ERROR);
        }
        Users user = new Users();
        user.setId(userId);
        user.setAvatarUrl(image);
        updateById(user);
        return Result.success(image);
    }

    /**
     * 更新用户信息
     *
     */
    @Override
    public Result updateUserData(Users users) {

        Users user = AppThreadLocalUtil.getUser();
        // : 校验参数
        if (users == null || user.getId() == null ) {
            return Result.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        // : 更新用户信息
        updateById(users);
//        update(users, new QueryWrapper<Users>().eq("openid", users.getOpenid()));
        return Result.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 关注用户
     *
     */
    @Override
    public Result focus(FocusBehaviorDto dto) {
        Users user = AppThreadLocalUtil.getUser();
        if (user == null ||user.getId() == null) {
            return Result.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 1.基于前端的参数，判断是执行收藏还是取消收藏
        boolean success = dto.isOperation() ? focuss(dto) : unfocus(dto) ;
        if (!success) {
            return Result.errorResult(AppHttpCodeEnum.DATA_EXIST);
        }
        // 3.如果执行成功，统计收藏总数
        Long focusTimes = redisTemplate.opsForSet()
                .size(BehaviorConstants.FOCUS_BEHAVIOR + user.getId().toString());
        // 4.更新数据库中的收藏数
        int focus = Objects.requireNonNull(focusTimes).intValue();
        lambdaUpdate().set(Users::getFans, focus).eq(Users::getId,user.getId()).update();
        String key = BehaviorConstants.FOCUS_BEHAVIOR + BehaviorConstants.TOTAL;
        // 4.缓存点总数到Redis
        redisTemplate.opsForZSet().add(
                key,
                user.getId().toString(),
                focusTimes
        );
        return Result.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private boolean unfocus(FocusBehaviorDto dto) {
        // 1.获取用户id
        Integer userId = AppThreadLocalUtil.getUser().getId();
        // 2.获取Key
        String key = BehaviorConstants.FOCUS_BEHAVIOR + dto.getFocusId().toString();
        // 3.执行SREM命令
        Long result = redisTemplate.opsForSet().remove(key, userId.toString());
        return result != null && result > 0;
    }

    private boolean focuss(FocusBehaviorDto dto) {
        // 1.获取用户id
        Integer userId = AppThreadLocalUtil.getUser().getId();
        // 2.获取Key
        String key = BehaviorConstants.FOCUS_BEHAVIOR + dto.getFocusId().toString() ;
        // 3.执行SADD命令
        Long result = redisTemplate.opsForSet().add(key, userId.toString());
        return result != null && result > 0;
    }


}
